package org.apache.struts.ehr.medical_records.action;

import java.util.ArrayList;
import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.axiom.om.OMElement;
import org.apache.struts.ehr.medical_records.model.Address;
import org.apache.struts.ehr.medical_records.model.AdmitPatient;
import org.apache.struts.ehr.medical_records.model.Bht;
import org.apache.struts.ehr.medical_records.model.Guardian;
import org.apache.struts.ehr.medical_records.model.GuardianForPatientDetails;
import org.apache.struts.ehr.medical_records.model.HL7Message;
import org.apache.struts.ehr.medical_records.model.MedicalRecords;
import org.apache.struts.ehr.medical_records.model.PatientRecords;
import org.apache.struts.ehr.medical_records.model.ReplyMessage;
import org.apache.struts.ehr.patient_details.model.Patient;
import org.apache.struts.ehr.patient_details.model.PatientDetails;
import org.apache.struts2.components.ActionError;
import org.apache.struts2.dispatcher.mapper.ActionMapping;

import ca.uhn.hl7v2.model.DataTypeException;
import ca.uhn.hl7v2.model.v251.message.ADR_A19;
import ca.uhn.hl7v2.model.v251.segment.PID;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

import com.earogya.Constants;
import com.earogya.communicate.Communicator;
import com.earogya.logic.medical_records.CreateADT01;
import com.earogya.logic.medical_records.ParseReply;
/***
 * This class contains the struts action to admit a patient.
 * @author Chamendri
 *
 */
public class AdmitPatientAction extends ActionSupport{

	private AdmitPatient admit;
	private Date date;
	private ReplyMessage replyMessage;
	private Patient details;
	private PatientRecords records;
	
	public Patient getDetails() {
		return details;
	}

	public PatientRecords getRecords() {
		return records;
	}

	public ReplyMessage getReplyMessage() {
		return replyMessage;
	}

	public AdmitPatient getAdmit() {
		return admit;
	}

	public void setAdmit(AdmitPatient admit) {
		this.admit = admit;
	}

	/**
	 * Overrides the execute method is ActionSupport interface
	 * When the action occurs this method is executed.
	 * returns ERROR if there is an error while sending, receiving or processing the received message.
	 * returns SUCCESS if there are no errors.
	 */
	public String execute() throws Exception {
		Map<String, Object> session=ActionContext.getContext().getSession();
		replyMessage=new ReplyMessage();
		replyMessage.setMessage(Constants.EMPTY);
		CreateADT01 createMessage=new CreateADT01(admit);
		String msg=createMessage.createMessage(Constants.SENDING_FACILITY);
		if(!msg.equals(null)){
			Communicator c=new Communicator();
			String reply=c.sendMessage(msg);
			if(!reply.equals(Constants.NO_REPLY)){
				ParseReply parse=new ParseReply();
				replyMessage=(ReplyMessage)parse.parseMessage(reply);
				if(replyMessage.getMessage().equals(Constants.SUCCESS)){
					PatientDetails patient_detials=new PatientDetails();
					patient_detials.getPatient().setPatientId(admit.getPatient_id());
					com.earogya.logic.patient_details.CreateQRYA19 qry=new com.earogya.logic.patient_details.CreateQRYA19(patient_detials);
					String msg_patient_details=qry.createMessage(Constants.SENDING_FACILITY);
					if(!msg_patient_details.equals(null)){
						Communicator c1=new Communicator();
						String reply1=c1.sendMessage(msg_patient_details);
						if(!reply1.equals(Constants.NO_REPLY)){
							ParseReply parse1=new ParseReply();
							try{
								ADR_A19 adr=(ADR_A19)parse1.parseMessage(reply1);
								this.setValuestoPatientDetails(adr);
								this.addDetails();
							}catch(ClassCastException e){
								replyMessage=(ReplyMessage)parse.parseMessage(reply1);
								return ERROR;
							}
						}else{
							replyMessage.setMessage(reply1);
							return ERROR;
						}
					}else{
						replyMessage.setMessage("Error while creating message");
						return ERROR;
					}
				}else{
					replyMessage.setMessage(replyMessage.getMessage());
					return ERROR;
				}
			}else{
				replyMessage.setMessage(reply);
				return ERROR;
			}
		}
		else{
			replyMessage.setMessage("failed to create message");
			return ERROR;
		}
		replyMessage.setMessage(Constants.EMPTY);
		return SUCCESS;
	}
	
	/**
	 * Process the ADR A19 message and add the values to Patient class.
	 * @param adr object of an ADR_A19 message
	 * @throws DataTypeException
	 */
	private void setValuestoPatientDetails(ADR_A19 adr) throws DataTypeException{
		this.details=new Patient();
		PID pid=adr.getQUERY_RESPONSE().getPID();
		if(pid.getDateTimeOfBirth().getTime().getValue()==null){}
		else{
			details.setBirthTime(pid.getDateTimeOfBirth().getTime().getValueAsDate());
		}
		details.setGender(pid.getAdministrativeSex().getValue());
		String prefix=pid.getPatientName(0).getPrefixEgDR().getValue();
		String givenName=pid.getPatientName(0).getGivenName().getValue();
		String familyName=pid.getPatientName(0).getFamilyName().getSurname().getValue();
		if(prefix==null || prefix.equals("null")){
			prefix="";
		}
		if(givenName==null || givenName.equals("null")){
			givenName="";
		}
		if(familyName==null || familyName.equals("null")){
			familyName="";
		}
		details.setGivenName(prefix+" "+givenName+" "+familyName);
		
	}
	
	/**
	 * Add values to PatientRecords class from Admit object.
	 */
	private void addDetails(){
		records=new PatientRecords();
		records.setAdmission_date(admit.getAdmission_date());
		records.setAdmit_reason(admit.getAdmit_reason());
		records.setAdmiting_officer(admit.getAdmiting_officer());
		records.setBed(admit.getBed());
		records.setPatient_id(admit.getPatient_id());
		records.setWard(admit.getWard());
		
		GuardianForPatientDetails guardian=new GuardianForPatientDetails();
		guardian.setFurthur_names(admit.getGuardian().getFurthur_names());
		guardian.setGiven_name(admit.getGuardian().getGiven_name());
		guardian.setGuardian_relationship(admit.getGuardian().getGuardian_relationship());
		guardian.setNic_no(admit.getGuardian().getNic_no());
		guardian.setPrefix(admit.getGuardian().getPrefix());
		guardian.setSurname(admit.getGuardian().getSurname());
		ArrayList<String> telephone=new ArrayList<String>();
		telephone.add(admit.getGuardian().getTelephoneNumbers());
		guardian.setTelephoneNumbers(telephone);
		ArrayList<Address> address=new ArrayList<Address>();
		address.add(admit.getGuardian().getAddresses());
		guardian.setAddresses(address);
		ArrayList<String> email=new ArrayList<String>();
		email.add(admit.getGuardian().getEmail());
		guardian.setEmail(email);
		records.setGuardian(guardian);
		
		ArrayList<MedicalRecords> medicalRecords=new ArrayList<MedicalRecords>();
		MedicalRecords mRec=new MedicalRecords();
		if(!admit.getDiagnosis().equals("")){
			mRec.setDiagosis(admit.getDiagnosis());
			mRec.setDiagnosingDate(admit.getAdmission_date());
			mRec.setDiagnosingClinicianId(admit.getAdmiting_officer());
		}
		if(!admit.getObservation().equals("")){
			mRec.setObservation(admit.getObservation());
			mRec.setObservationdate(admit.getAdmission_date());
			mRec.setObserverId(admit.getAdmiting_officer());
		}
		mRec.setPatientId(admit.getPatient_id());
		medicalRecords.add(mRec);
		records.setMedicalRecords(medicalRecords);
		
		Bht bht=new Bht();
		bht.setConsultant_id(admit.getConsultant_id());
		bht.setCurrent_bed(admit.getBed());
		bht.setCurrent_ward(admit.getWard());
		records.setBht(bht);
	}
	
	/**
	 * Overrides the validate method in ActionSupport interface.
	 * Validates the input fields for correct input.
	 */
	public void validate(){
		if(admit.getPatient_id().length()==0){
			addFieldError( "admit.patient_id", "Patient ID required" );
		}
		else if(!this.isInteger(admit.getPatient_id())){
			addFieldError( "admit.patient_id", "Incorrect patient ID format." );
		}
		if(admit.getAdmiting_officer().length()==0){
			addFieldError("admit.admiting_officer", "Admiting Officer ID required");
		}
		if(!this.isInteger(admit.getBed()) && admit.getBed().length()>0){
			addFieldError("admit.bed", "Incorrect bed");
		}
		if(admit.getWard().length()==0){
			addFieldError("admit.ward", "Ward required");
		}
		else if(!this.isInteger(admit.getWard())){
			addFieldError("admit.ward", "Incorrect ward");
		}
		if(admit.getAdmit_reason().length()==0){
			addFieldError("admit.admit_reason", "Admit reasion required");
		}
		if(admit.getConsultant_id().length()==0){
			addFieldError("admit.consultant_id", "Consulatant ID required");
		}
		if(admit.getAdmission_date()==null){
			addFieldError("admit.admission_date", "Admission date cannot be empty");
		}
		if(admit.getObservation().length()==0){
			addFieldError("admit.observation", "Observations cannot be empty");
		}
		if(admit.getGuardian().getPrefix().equals("0")){
			addFieldError("admit.guardian.prefix", "Please select a prefix");
		}
		if(admit.getGuardian().getSurname().length()==0){
			addFieldError("admit.guardian.surname", "Please enter a name");
		}
		if(!this.isCorrectNICNo(admit.getGuardian().getNic_no())){
			addFieldError("admit.guardian.nic_no", "Incorrect NIC number");
		}
		if(admit.getGuardian().getAddresses().getHouse_number().length()==0){
			addFieldError("admit.guardian.addresses.house_number", "House number cannot be empty");
		}
		if(admit.getGuardian().getAddresses().getCity_1().length()==0){
			addFieldError("admit.guardian.addresses.city_1", "This field cannot be empty");
		}
		if(!this.isCorrectTelephoneNumber(admit.getGuardian().getTelephoneNumbers()) && admit.getGuardian().getTelephoneNumbers().length()>0){
			addFieldError("admit.guardian.telephoneNumbers", "Incorrect number");
		}
		if(!this.isCorrectEmailAddress(admit.getGuardian().getEmail()) && admit.getGuardian().getEmail().length()>0){
			addFieldError("admit.guardian.email", "Incorrect email");
		}
		if(admit.getGuardian().getGuardian_relationship().equals("0")){
			addFieldError("admit.guardian.guardian_relationship", "This field is required");
		}
	}
	
	/**
	 * Check if the given string is an integer.
	 * @param value
	 * @return true is the value is an integer
	 */
	private Boolean isInteger(String value){
		Boolean isInteger=false;
		try{
			int intValue=Integer.parseInt(value);
			isInteger=true;
		}catch(NumberFormatException e){
			isInteger=false;
		}
		return isInteger;
	}
	
	/**
	 * Check if the given string is a correct NIC number
	 * @param nic 
	 * @return true if the string is a correct NIC number
	 */
	private Boolean isCorrectNICNo(String nic){
		Boolean isCorrectNicNo=false;
		int length=nic.length();
		if(length==10){
			if((nic.charAt(9)=='v' || nic.charAt(9)=='V')||(nic.charAt(9)=='x' || nic.charAt(9)=='X')){
				isCorrectNicNo=true;
			}
		}
		return isCorrectNicNo;
	}
	
	/**
	 * Check if the given string is a correct telephone number
	 * @param number
	 * @return true if correct telephone number
	 */
	private Boolean isCorrectTelephoneNumber(String number){
		Boolean isCorrectNumber=false;
		String[] numbers=number.split(",");
		for(int i=0; i<numbers.length; i++){
			String num=numbers[i].trim();
			if(num.matches("[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]")){
				isCorrectNumber=true;
			}else if(num.matches("[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9][0-9][0-9][0-9]")){
				isCorrectNumber=true;
			}
		}
		return isCorrectNumber;
	}
	
	/**
	 * Check if the given string a correct email address
	 * @param email
	 * @return true if the string is a correct email address
	 */
	private Boolean isCorrectEmailAddress(String email){
		Boolean isCorrectEmail=false;
		if(email.matches("[0-9a-z]+@[a-z]+.[a-z]+")){
			isCorrectEmail=true;
		}
		return isCorrectEmail;
	}
}
